# -*- coding: utf-8 -*-
# @Time    : 2021/1/14 10:23
# @Author  : DuJiabao
# @Project : BaoZaiFanYiWuJianCe
# @FileName: SocketThread.py
# @Software: PyCharm
# @Desc    :
from multiprocessing import Queue
from GlobalStatement import *
import socket
from crc16 import *


def createUdp(local_address: str, local_port: int) -> socket.socket:
    """
    创建udp服务
    :param local_address: 本地地址
    :param local_port: 本地端口
    :return: socket创建的upd服务
    """
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 绑定端口:
    s.bind((local_address, local_port))
    print(f'Bind UDP on {local_address}:{local_port} ...')
    return s


def hexToBytes(hex_string: str) -> bytes:
    """
    将String保存的hex，转成bytes
    :rtype: object
    :param hex_string: "0xAA"
    :return: b"\xaa"
    """
    if hex_string[:2] == "0x" or hex_string[:2] == "0X":
        hex_string = hex_string[2:]
    return bytes.fromhex(hex_string)


def decode(massage: bytes) -> tuple:
    """
    解析接受回来的消息
    :param massage: b"\xaaa0010001037ed8 "
    :return: 包头，包命令，数据长度，数据内容,CRC校验
    """
    hex_message = massage.hex()  # str类型
    # TODO: CRC
    return hex_message[:2], hex_message[2:6], \
           hex_message[6:10], hex_message[10:-4], \
           hex_message[-4:]


class SocketThread(object):
    def __init__(self, local_address: str, local_port: int):
        """
        初始化udp的socket
        :param local_address: 本地地址
        :param local_port: 本地端口
        """
        self.local_address = local_address
        self.local_port = local_port
        self.udp_socket = createUdp(local_address, local_port)
        print(f'Bind UDP on {local_address}: {local_port}')

    def callback(self):
        """
        接收更新炉头开合状态的线程
        :return:
        """
        while True:
            data, addr = self.udp_socket.recvfrom(1024)
            s = 'Received from %s:%s.' % addr
            print(s)
            put_message(s)
            data = decode(data)
            # 若收到的信息CRC校验之后是正确的
            if data:
                # TODO: 判断收到的信息是回复的，还是查询的
                _, _, length, data, _ = data
                length = int(length)
                assert length == lutou_num, "炉头数目不对"
                self.update_open_state(data)  # 更新炉头状态
                update_lutou_open_state_queue.put(1)  # 告诉拍照线程，已经更新了开合状态了
                # 等到更新异物状态
                while update_lutou_yiwu_state_queue.empty():
                    pass
                message = self.update_yiwu_message()
                self.udp_socket.send(message, addr)  # 返回当今的异物状态
                s = "Send update yiwu state to %s:%s" % addr
                print(s)
                put_message(s)

    def update_open_state(self, data):
        """
        根据接受到的信息，更新炉头开合状态
        :param data:
        :return:
        """
        for i in range(lutou_num):
            state = data[2 * i:2 * i + 1]
            if state == "01":
                lutou_open_states[i] = lutou_open_state_t.open
            elif state == "00":
                lutou_open_states[i] = lutou_open_state_t.closed

    def update_yiwu_message(self) -> bytes:
        """
        将目前的状态，编写成bytes格式的消息，发送给煲仔饭机器人
        :return:
        """
        head = "AA"
        command = "A001"
        data_length = hex(lutou_num)[2:].upper()  # 根据炉头个数，决定数据长度
        message = head + command + data_length
        for state in lutou_yiwu_states:
            if state == lutou_yiwu_states.empty:
                message += "00"
            elif state == lutou_yiwu_states.exist:
                message += "01"
            else:
                message += "02"
        # TODO: CRC
        return hexToBytes(message)


if __name__ == "__main__":
    pass
